package com.AuthServer.service.impl;

import com.AuthServer.common.Result;
import com.AuthServer.convertor.PermissonConverter;
import com.AuthServer.convertor.WhetherConverter;
import com.AuthServer.exception.CaptchaExpiredException;
import com.AuthServer.exception.CaptchaIncorrectException;
import com.AuthServer.exception.JobNumberNotExistException;
import com.AuthServer.exception.UserStatusInvalidException;
import com.AuthServer.mapper.PermMapper;
import com.AuthServer.mapper.UserMapper;
import com.AuthServer.pojo.entity.Perm;
import com.AuthServer.pojo.entity.Teacher;
import com.AuthServer.pojo.entity.User;
import com.AuthServer.pojo.form.*;
import com.AuthServer.pojo.join.U_P;
import com.AuthServer.pojo.query.UserQuery;
import com.AuthServer.pojo.vo.UserInfoVo;
import com.AuthServer.pojo.vo.UserPermVo;
import com.AuthServer.pojo.vo.UserVo;
import com.AuthServer.service.SecretService;
import com.AuthServer.service.U_PService;
import com.AuthServer.service.UserService;
import com.AuthServer.utils.GraphicalCaptchaUtil;
import com.AuthServer.utils.JsonUtil;
import com.AuthServer.utils.JwtUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import jakarta.mail.internet.AddressException;
import jakarta.mail.internet.InternetAddress;
import jakarta.mail.internet.MimeUtility;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private SecretService secretService;
    @Autowired
    @Qualifier("default")
    private RedisTemplate<String, Object> template;
    @Autowired
    private JavaMailSender mailSender;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private U_PService u_pService;
    @Autowired
    private PermMapper permMapper;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Value("${web.url}")
    private String baseEmailVl;

    @Override
    @Transactional
    public Result<String> login(LoginForm loginForm) throws JsonProcessingException {
        String graphicalCaptcha_key = loginForm.getUserId() + "_code";
        String graphicalCaptcha = (String) template.opsForValue().get(graphicalCaptcha_key);
        if (graphicalCaptcha == null) {
            throw new CaptchaExpiredException();
        }
        if (loginForm.getGraphicalCaptcha().equalsIgnoreCase(graphicalCaptcha)) {
            template.delete(graphicalCaptcha_key);
            //将用户名和密码存入authenticationToken，调用authenticate方法进行验证
            UsernamePasswordAuthenticationToken authenticationToken =
                    new UsernamePasswordAuthenticationToken(loginForm.getUserId(), loginForm.getPassword());
            Authentication authenticate = authenticationManager.authenticate(authenticationToken);
            User user = (User) authenticate.getPrincipal();
            if (user.getDeleteFlag() == 1) {
                throw new UserStatusInvalidException();
            }
            String userInfo_key = "user_" + user.getUserId();
            String userInfo = JsonUtil.serialize(user);
            template.opsForValue().set(userInfo_key, userInfo, 6, TimeUnit.HOURS);
            return Result.success(JwtUtil.createJwt(userInfo_key, template, secretService));
        } else {
            throw new CaptchaIncorrectException();
        }
    }

    @Override
    @Transactional
    public Result<String> getGraphicalCaptcha(String userId) throws IOException {
        return GraphicalCaptchaUtil.getRandomCode(userId, template);
    }

    @Override
    @Transactional
    public Result<?> getEmailCaptcha(String email) throws UnsupportedEncodingException, AddressException {
        String emailCaptcha_key = email + "_code";
        if (template.opsForValue().get(emailCaptcha_key) == null) {
            Random rand = new Random();
            String emailCaptcha = IntStream.range(0, 6)
                    .mapToObj(i -> rand.nextInt(10))
                    .map(String::valueOf)
                    .collect(Collectors.joining());
            SimpleMailMessage message = new SimpleMailMessage();
            message.setSubject("学院岗位聘任与考核管理系统邮箱验证码");
            message.setText("尊敬的: " + email + "您的验证码为: " + emailCaptcha + ",有效期2分钟，请不要把验证码信息泄露给其他人,如非本人请勿操作");
            message.setTo(email);
            message.setFrom(new InternetAddress(MimeUtility.encodeText("理塘丁真") + "<3791228781@qq.com>").toString());
            mailSender.send(message);
            template.opsForValue().set(emailCaptcha_key, emailCaptcha, 2, TimeUnit.MINUTES);
            return Result.success(null);
        } else {
            return Result.fail(107, "请求频繁，请稍后重试", null);
        }
    }

    @Override
    @Transactional
    public Result<String> verifyInfo(VerifyInfoForm verifyInfoForm, Teacher teacher) {
        String graphicalCaptcha_key = verifyInfoForm.getUserId() + "_code";
        String graphicalCaptcha = (String) template.opsForValue().get(graphicalCaptcha_key);
        if (graphicalCaptcha == null) {
            throw new CaptchaExpiredException();
        }
        if (verifyInfoForm.getGraphicalCaptcha().equalsIgnoreCase(graphicalCaptcha)) {
            template.delete(graphicalCaptcha_key);
            LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
            if (teacher == null) {
                throw new JobNumberNotExistException();
            } else if (userMapper.selectOne(wrapper.eq(User::getUserId, verifyInfoForm.getUserId())) != null) {
                return Result.fail(109, "账号已被激活", null);
            } else if (verifyInfoForm.getTeacherName().equals(teacher.getTeacherName())
                    && verifyInfoForm.getIdCardNumber().equals(teacher.getIdCardNumber())) {
                String userVerifyInfo_key = "vi_" + verifyInfoForm.getUserId();
                Map<String, Object> map = new HashMap<>();
                map.put("userId", verifyInfoForm.getUserId());
                map.put("operate", "verifyInfo");
                map.put("enable", true);
                template.opsForValue().set(userVerifyInfo_key, map, 30, TimeUnit.MINUTES);
                return Result.success(JwtUtil.createJwt(userVerifyInfo_key, template, secretService));
            } else {
                return Result.fail(110, "校验失败", null);
            }
        } else {
            throw new CaptchaIncorrectException();
        }
    }

    @Override
    @Transactional
    public Result<String> bindEmail(EmailForm emailForm) {
        String userVerifyInfo_key = JwtUtil.parseJwt(emailForm.getVerifyInfoToken(), template, secretService);
        Map<String, Object> userVerifyInfo = (Map<String, Object>) template.opsForValue().get(userVerifyInfo_key);
        if (userVerifyInfo == null) {
            return Result.fail(114, "操作超时", null);
        }
        if (userVerifyInfo.containsKey("userId") && userVerifyInfo.get("userId").equals(emailForm.getUserId()) &&
                userVerifyInfo.containsKey("operate") && "verifyInfo".equals(userVerifyInfo.get("operate")) &&
                userVerifyInfo.containsKey("enable") && userVerifyInfo.get("enable").equals(true)) {
            String emailCaptcha_key = emailForm.getEmail() + "_code";
            String emailCaptcha = (String) template.opsForValue().get(emailCaptcha_key);
            if (emailCaptcha == null) {
                throw new CaptchaExpiredException();
            }
            if (emailForm.getEmailCaptcha().equals(emailCaptcha)) {
                template.delete(emailCaptcha_key);
                LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
                if (userMapper.selectOne(wrapper.eq(User::getEmail, emailForm.getEmail())) == null) {
                    String userBindEmail_key = "be_" + emailForm.getUserId();
                    Map<String, Object> map = new HashMap<>();
                    map.put("userId", emailForm.getUserId());
                    map.put("email", emailForm.getEmail());
                    map.put("operate", "bindEmail");
                    map.put("enable", true);
                    template.opsForValue().set(userBindEmail_key, map, 30, TimeUnit.MINUTES);
                    return Result.success(JwtUtil.createJwt(userBindEmail_key, template, secretService));
                } else {
                    return Result.fail(112, "该邮箱已被绑定", null);
                }
            } else {
                throw new CaptchaIncorrectException();
            }
        } else {
            return Result.fail(115, "非法请求", null);
        }
    }

    @Override
    @Transactional
    public Result<?> setPassword(PasswordForm passwordForm) {
        // 检查是否提供了绑定邮箱的 token
        if (passwordForm.getBindEmailToken() != null && !passwordForm.getBindEmailToken().isEmpty()) {
            String userBindEmail_key = JwtUtil.parseJwt(passwordForm.getBindEmailToken(), template, secretService);
            Map<String, Object> map = (Map<String, Object>) template.opsForValue().get(userBindEmail_key);
            if (map == null) {
                return Result.fail(114, "操作超时", null);
            }
            if (map.containsKey("userId") && map.get("userId").equals(passwordForm.getUserId()) &&
                    map.containsKey("email") && map.get("email").equals(passwordForm.getEmail()) &&
                    map.containsKey("operate") && "bindEmail".equals(map.get("operate")) &&
                    map.containsKey("enable") && map.get("enable").equals(true)) {
                userMapper.insert(new User(null,
                        passwordForm.getUserId(),
                        passwordEncoder.encode(passwordForm.getPassword()),
                        passwordForm.getEmail(), 1, 0, 1, null, null));
                u_pService.save(new U_P(null, passwordForm.getUserId(), 1));
                List<String> keys = new ArrayList<>();
                keys.add("vi_" + passwordForm.getUserId());
                keys.add("be_" + passwordForm.getUserId());
                template.delete(keys);
                return Result.success(null);
            } else {
                return Result.fail(115, "非法请求", null);
            }
        } else {
            // 没有提供绑定邮箱的 token，直接设置密码
            userMapper.insert(new User(null,
                    passwordForm.getUserId(),
                    passwordEncoder.encode(passwordForm.getPassword()),
                    null, 1, 0, 1, null, null)); // Email 设置为 null
            u_pService.save(new U_P(null, passwordForm.getUserId(), 1));
            List<String> keys = new ArrayList<>();
            keys.add("vi_" + passwordForm.getUserId());
            template.delete(keys);
            return Result.success(null);
        }
    }


    @Override
    public Result<?> verifyEmail(BindEmailForm bindEmailForm) throws JsonProcessingException {
        User user = new User();
        String user_key = "user_" + bindEmailForm.getUserId();
        String userInfo  = (String) template.opsForValue().get(user_key);
        if (userInfo != null) {
            user = JsonUtil.deserialize(userInfo,User.class);
        }
        else {
            user = userMapper.selectUserById(bindEmailForm.getUserId());
            String userInfo2 = JsonUtil.serialize(user);
            template.opsForValue().set(user_key, userInfo2, 30, TimeUnit.MINUTES);
        }
        String email = user.getEmail();
        if (bindEmailForm.getEmail().equals(email)) {
            return Result.success("校验通过，请进行下一步操作");
        } else {
            return Result.fail(110,"请输入正确的邮箱",null);
        }
    }

    @Override
    public Result<?> bindEmailCaptcha(BindCodeForm bindCodeForm) {
        if (!bindCodeForm.getCode().isEmpty() && !bindCodeForm.getCode().isBlank()) {
            String emailCaptcha_key = bindCodeForm.getEmail() + "_code";
            String emailCaptcha = (String) template.opsForValue().get(emailCaptcha_key);
            if (bindCodeForm.getCode().equals(emailCaptcha)) {
                template.delete(emailCaptcha_key);
                return Result.success("校验通过，请进行下一步操作");
            } else {
                return Result.fail(110, "验证码错误", null);
            }
        }
        return Result.fail(115, "非法请求", null);
    }

    @Override
    public Result<?> updatePassword(UpdatePasswordForm updatePasswordForm) throws JsonProcessingException {
        String user_key = "user_" + updatePasswordForm.getUserId();
        String userInfo  = (String) template.opsForValue().get(user_key);
        User user = JsonUtil.deserialize(userInfo,User.class);
        if (user != null) {
            String oldPassword = user.getPassword();
            if (!passwordEncoder.matches(updatePasswordForm.getNewPassword(), oldPassword)) {
                if (updatePasswordForm.getNewPassword().equals(updatePasswordForm.getRePassword())) {
                    UpdateWrapper<User> wrapper = new UpdateWrapper<>();
                    wrapper.set("password",passwordEncoder.encode(updatePasswordForm.getNewPassword()))
                            .eq("user_id",updatePasswordForm.getUserId());
                    userMapper.update(null,wrapper);
                    template.delete(user_key);
                    return Result.success("重置密码成功，请重新登录");
                } else {
                    return Result.fail(116,"两次密码不同",null);
                }
            } else {
                return Result.fail(116,"新密码与原密码相同",null);
            }
        }
        return Result.fail(106,"账号出现异常，请联系维护人员",null);
    }


    @Override
    public Result<?> getUserList(Long pageNumber, Long pageSize) {
        Page<User> page = new Page<>(pageNumber,pageSize);
        List<User> userList = userMapper.selectPage(page,null).getRecords();
        System.out.println(userList);
        List<UserVo> userVoList = userList.stream().map(UserVo::new).collect(Collectors.toList());
        Map<String, Object> data = new HashMap<>();
        data.put("totals",page.getTotal());
        data.put("currentPages",page.getCurrent());
        data.put("pageNumber",page.getPages());
        data.put("rows",userVoList);
        return Result.success(data);
    }

    @Override
    public Result<?> getUserPerm(String userId) {
        LambdaQueryWrapper<U_P> u_pLambdaQueryWrapper = new LambdaQueryWrapper<>();
        List<U_P> list = u_pService.list(u_pLambdaQueryWrapper.eq(U_P::getUserId, userId));
        List<Integer> permIdList = list.stream().map(U_P::getPermId).collect(Collectors.toList());
        // LambdaQueryWrapper<Perm> permLambdaQueryWrapper = new LambdaQueryWrapper<>();
        // List<Perm> permList = permMapper.selectList(permLambdaQueryWrapper.in(Perm::getPermId,permIdList));
        return Result.success(permIdList);
    }

    @Override
    public Result<?> getPerm() {
        List<Perm> permList = permMapper.selectList(null);
        return Result.success(permList);
    }

    @Override
    public Result<?> addUserPerm(String userId, Integer[] permIds) {
        LambdaQueryWrapper<Perm> permLambdaQueryWrapper = new LambdaQueryWrapper<>();
        List<Perm> permList = permMapper.selectList(permLambdaQueryWrapper.in(Perm::getPermId,Arrays.asList(permIds)));
        for (Perm perm : permList) {
            if (perm.getAvailable() == 0) {
                return Result.fail(403,"该权限无法获得" + perm.getPermDetail(),null);
            }
        }
        List<U_P> collect = permList.stream().map(perm -> new U_P(null, userId, perm.getPermId())).collect(Collectors.toList());
        u_pService.saveBatch(collect);
        return Result.success(null);
    }

    @Override
    public Result<?> deleteUserPerm(String userId, Integer[] permIds) {
        LambdaQueryWrapper<Perm> permLambdaQueryWrapper = new LambdaQueryWrapper<>();
        List<Perm> permList = permMapper.selectList(permLambdaQueryWrapper.in(Perm::getPermId,Arrays.asList(permIds)));
        for (Perm perm : permList) {
            if (perm.getAvailable() == 0) {
                return Result.fail(403,"该权限无法删除" + perm.getPermDetail(),null);
            }
        }
        LambdaQueryWrapper<U_P> u_pLambdaQueryWrapper = new LambdaQueryWrapper<>();
        u_pService.remove(u_pLambdaQueryWrapper.eq(U_P::getUserId,userId).in(U_P::getPermId,Arrays.asList(permIds)));
        return Result.success(null);
    }

    @Override
    @Transactional
    public Result<UserInfoVo> getOneByUserId(String userId) {
        /*User user = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getUserId, userId));
        // 根据userId查询teacher表中的teacherName
        user.setUsername(userMapper.getTeacherNameById(userId));
        if (user == null) {
            return Result.fail(108, "用户不存在", null);
        }*/
        User user = userMapper.selectUserById(userId);
        user.setUsername(userMapper.getTeacherNameById(userId));
        UserInfoVo userInfoVo = new UserInfoVo();
        BeanUtils.copyProperties(user, userInfoVo);
        return Result.success(userInfoVo);
    }

    @Override
    public Result<?> updateStatus(String userId, String status) {
        User user = userMapper.selectUserById(userId);
        if (user == null) {
            throw new JobNumberNotExistException();
        }
        Integer st = new WhetherConverter().convertToJavaData(status);
        userMapper.updateStatus(st,userId);
        return Result.success("更新状态成功");
    }

    @Override
    public Result<Map<String,Object>> searchUserList(UserQuery userQuery) {
        if (userQuery.getStatus() != null && !userQuery.getStatus().isEmpty() && !userQuery.getStatus().isBlank()) {
            userQuery.setStatus(new WhetherConverter().convertToJavaData(userQuery.getStatus()).toString());
        }
        if (userQuery.getPremission() != null && !userQuery.getPremission().isEmpty() && !userQuery.getPremission().isBlank()) {
            userQuery.setPremission(new PermissonConverter().convertToJavaData(userQuery.getPremission()).toString());
        }
        Page<UserPermVo> page = new Page<>(userQuery.getCurrentPage(),userQuery.getPageSize());
        userMapper.searchUserList(page,userQuery);
        Map<String,Object> data = new HashMap<>();
        data.put("total",page.getTotal());
        data.put("currentPage",page.getCurrent());
        data.put("pageNumber",page.getPages());
        data.put("records",page.getRecords());
        return Result.success(data);
    }

    @Override
    public Result<?> removeUserById(String userId) {
        User user = userMapper.selectUserById(userId);
        if (user == null) {
            return Result.fail(108,"用户不存在",null);
        }
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id",userId);
        userMapper.delete(queryWrapper);
        return Result.success("删除用户成功");
    }

    @Override
    public Result<?> removeBatchUsers(List<String> userIds) {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.in("user_id",userIds);
        userMapper.delete(wrapper);
        List<String> delUserIds = new ArrayList<>(userIds.size());
        //删除用户之后，需要删除在redis中的数据
        for (int i = 0; i < userIds.size(); i++) {
            delUserIds.add("user_"+userIds.get(i));
        }
        template.delete(delUserIds);
        return Result.success("批量删除用户成功");
    }

}
